﻿using System;
using System.Text;

using Exif.Various;

namespace Exif.Interfaces
{
	///<summary>
	///
	///</summary>
	public interface IImageReader
	{
		#region Свойства

		///<summary>
		///Объект синхронизации
		///</summary>
		object SyncRoot { get; }

		///<summary>
		///Размер изображения (в байтах)
		///</summary>
		long Length { get; }

		///<summary>
		///Текущая позиция в потоке чтения
		///</summary>
		long Position { get; }

		///<summary>
		///Порядок байт при чтении
		///</summary>
		Endian Endian { get; set; }

		#endregion

		#region Not sequential

		///<summary>
		///
		///</summary>
		///<param name="offset"></param>
		///<returns></returns>
		UInt16 ReadCode(long offset);

		///<summary>
		///Считывает <param name="count"/> количество байт
		///</summary>
		///<returns>Массив байт (длины, равной <paramref name="count"/> или меньшей, если в
		///потоке осталось меньше несчитанных байт)</returns>
		byte[] ReadBytes(long offset, int count);

		///<summary>
		///
		///</summary>
		///<param name="offset"></param>
		///<returns></returns>
		byte ReadByte(long offset);

		///<summary>
		///
		///</summary>
		///<param name="offset"></param>
		///<returns></returns>
		Int16 ReadInt16(long offset);

		///<summary>
		///
		///</summary>
		///<param name="offset"></param>
		///<returns></returns>
		UInt16 ReadUInt16(long offset);

		///<summary>
		///
		///</summary>
		///<param name="offset"></param>
		///<returns></returns>
		Int32 ReadInt32(long offset);

		///<summary>
		///
		///</summary>
		///<returns></returns>
		UInt32 ReadUInt32(long offset);

		///<summary>
		///
		///</summary>
		///<param name="offset"></param>
		///<param name="length"></param>
		///<param name="encoding"></param>
		///<returns></returns>
		string ReadString(long offset, int length, Encoding encoding);

		///<summary>
		///
		///</summary>
		///<param name="offset"></param>
		///<returns></returns>
		Rational ReadRational(long offset);

		///<summary>
		///
		///</summary>
		///<param name="offset"></param>
		///<returns></returns>
		SRational ReadSRational(long offset);

		#endregion

		#region Sequential

		///<summary>
		///
		///</summary>
		///<returns></returns>
		UInt16 ReadCode();

		///<summary>
		///Считывает <param name="count"/> количество байт
		///</summary>
		///<returns>Массив байт (длины, равной <paramref name="count"/> или меньшей, если в
		///потоке осталось меньше несчитанных байт)</returns>
		byte[] ReadBytes(int count);

		///<summary>
		///
		///</summary>
		///<returns></returns>
		byte ReadByte();

		///<summary>
		///
		///</summary>
		///<returns></returns>
		Int16 ReadInt16();

		///<summary>
		///
		///</summary>
		///<returns></returns>
		UInt16 ReadUInt16();

		///<summary>
		///
		///</summary>
		///<returns></returns>
		Int32 ReadInt32();

		///<summary>
		///
		///</summary>
		///<returns></returns>
		UInt32 ReadUInt32();

		///<summary>
		///
		///</summary>
		///<param name="length"></param>
		///<param name="encoding"></param>
		///<returns></returns>
		string ReadString(int length, Encoding encoding);

		///<summary>
		///
		///</summary>
		///<returns></returns>
		Rational ReadRational();

		///<summary>
		///
		///</summary>
		///<returns></returns>
		SRational ReadSRational();

		///<summary>
		///Начинает последовательное чтение данных
		///</summary>
		///<param name="startOffset"></param>
		void BeginRead(long startOffset);

		///<summary>
		///Сдвигает текущую позицию на <paramref name="offset"/> байт.
		///</summary>
		///<param name="offset">Количество байт, на которое надо сдвинуть текущее положение</param>
		void Advance(long offset);

		///<summary>
		///Заканчивает последовательное чтение данных
		///</summary>
		void EndRead();

		#endregion

		#region Методы

		///<summary>
		///Сохраняет предыдущий порядок байт и устанавливает новый
		///</summary>
		///<param name="newEndian"></param>
		void PushEndian(Endian newEndian);

		///<summary>
		///Устанавливает предыдущий порядок байт
		///</summary>
		void PopEndian();

		///<summary>
		///Сохраняет предыдущее местоположение в потоке и устанавливает новое
		///</summary>
		///<param name="newPosition">Новое положение курсора</param>
		void PushPosition(long newPosition);

		///<summary>
		///Восстанавливает предыдущее положение курсора
		///</summary>
		void PopPosition();

		#endregion
	}
}